package com.wudizaba.nb.caffeine.service.serviceImpl;


import com.github.benmanes.caffeine.cache.*;
import com.wudizaba.nb.caffeine.config.MyCache;
import com.wudizaba.nb.caffeine.mapper.EmployeeMapper;
import com.wudizaba.nb.caffeine.po.Employee;
import com.wudizaba.nb.caffeine.service.CaffieineService;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor
public class CaffieineServiceImpl implements CaffieineService {

    private final EmployeeMapper employeeMapper;

    /**
     * 手动加载
     */
    @Override
    public void CaffieineTestOne() {
        Cache<String, Object> myCache = MyCache.getMyCache(1, 1000);
        String key = "2024:Key";
        String key1 = key + "1";
        // 使用getIfPresent方法从缓存中获取值。如果缓存中不存指定的值，则方法将返回 null
        System.out.println("=======使用getIfPresent方法从缓存中获取值。如果缓存中不存指定的值，则方法将返回 null=======");
        Object ifPresent = myCache.getIfPresent("1");
        System.out.println(ifPresent);


        // 也可以使用 get 方法获取值，该方法将一个参数为 key 的 Function 作为参数传入。如果缓存中不存在该 key
        // 则该函数将用于提供默认值，该值在计算后插入缓存中
        myCache.get(key1, s -> {
            Employee employee = employeeMapper.selectById(1);
            return employee.toString();
        });

        System.out.println(myCache.getIfPresent(key1));
        String key2 = key + "2";
        System.out.println("=======使用 put 方法向缓存中添加 key 和 value=======");
        myCache.put(key2, "1");

        System.out.println("=======使用 get 方法从缓存中获取指定的 key=======");
        System.out.println(myCache.getIfPresent(key2));

        // 使用 invalidate 方法从缓存中删除指定的 key
        System.out.println("=======使用 invalidate 方法从缓存中删除指定的 key=======");
        myCache.invalidate(key2);
        System.out.println(myCache.getIfPresent(key2));

        // 使用 invalidateAll 方法从缓存中删除所有的 key
        System.out.println("=======使用 invalidateAll 方法从缓存中删除所有的 key=======");
        myCache.invalidateAll();
        System.out.println(myCache.getIfPresent(key1));

    }

    /**
     * 同步加载
     */
    @Override
    public void CaffieineTestTwo() {
        LoadingCache<String, Object> myCache = Caffeine.newBuilder()
                .expireAfterWrite(100, TimeUnit.SECONDS)
                .maximumSize(100)
                .build(new CacheLoader<String, Object>() {
                    @Override
                    public @Nullable Object load(@NonNull String key) throws Exception {
                        return employeeMapper.selectById(1);
                    }
                });
        String key = "2024:Key";
        String key1 = key + "1";
        String key2 = key + "2";
        String key3 = key + "3";
        // 获取key对应的value，如果没有，会执行load方法加载到缓存中
        System.out.println("===获取key对应的value，如果没有，会执行load方法加载到缓存中===");
        Object value = myCache.get(key3);
        System.out.println("value = " + value);

        
        myCache.put(key2, "2");
        myCache.put(key3, "3");
        
        // 支持直接get一组值，支持批量查找
        System.out.println("===支持直接get一组值，支持批量查找===");
        Map<@NonNull String, @NonNull Object> all = 
                myCache.getAll(Arrays.asList(key1, key2, key3));
        System.out.println(all);


    }

    /**
     * 异步加载
     */
    @Override
    public void CaffieineTestThree() {
        AsyncCache<Object, Object> asyncCache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.SECONDS)
                .maximumSize(100)
                .executor(Executors.newSingleThreadExecutor())
                .buildAsync();


        String key = "2024:Key";
        String key1 = key + "1";
        // 异步加载
        CompletableFuture<Object> objectCompletableFuture = asyncCache.get(key1, s -> {
            System.out.println("线程："+Thread.currentThread().getName());
            Employee employee = employeeMapper.selectById(1);
            return employee.toString();
        });

        Object value = objectCompletableFuture.join();

        System.out.println(value);
        try {
            System.out.println("===开始睡眠===");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("=======异步加载=======");
        System.out.println(asyncCache.getIfPresent(key1));
    }
}
